package com.android.kaui;
//package com.android.kaui.view;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;

import android.util.Log;
import android.view.MotionEvent;
import android.widget.EditText;
import android.os.Handler;
import android.widget.Chronometer;
import android.os.CountDownTimer;
import android.widget.TabHost;

/**
 * A class which will make gesture recognition a lot easier!
 * @author MrSnowflake
 */
public class SnowGesture{
	private static final String TAG = "SnowGesture";

		/**
	 * The listener interface which is used to be called when a gesture is completed.
	 * @author MrSnowflake
	 */
	public interface GestureCompleteListener {
		/**
		 * This method will be called when a gesture is completed. The gesture will be 
		 * given as the parameter.
		 * @param gesture The gesture which just got completed.
		 */
		public void onGestureCompleted(String gesture);
	}
	
	/**
	 * The listener interface which is used to be called when a gesture got completed and 
	 * got recognized as a gesture you supplied by registerGesture(String gesture, GestureListener listener).
	 * @author MrSnowflake
	 */
	public interface GestureListener {
		/**
		 * This method will be called when the gesture got recognized.
		 */
		public void onRecognized();
	}
	
	/**
	 * To be deleted!!!!
	 * @param bool
	 */
	public SnowGesture(float minDist, boolean bool) {
		init();
		mDebug = bool;
		mMinDistance = minDist;
	}
		
	/**
	 * Default constructor, should be good for almost anyone.
	 */
	public SnowGesture() {
		init();
	}
	
	/**
	 * Constructor which allows to manually set the minimal distance between 2 point to be counted as valid, 
	 * to compensate for inaccuracies of the touch screen or input.
	 * @param minDist The minimal distance between 2 points to be counted as valid. (default 2.0)
	 */
	public SnowGesture(float minDist) {
		init();
		mMinDistance = minDist;
	}
	
	private void init() {
		mDebug = false;
		
		if (mGesture == null)
		mGesture = new String();
   		mStr = new String();mStr1 = new String();mStr2 = new String();mStr3 = new String();
		mStr4 = new String();mStr5 = new String();mStr6 = new String();mStr7 = new String();
		mGestureCompleteListeners = new ArrayList<GestureCompleteListener>();
		mGestureListeners = new HashMap<String, GestureListener>();
		mMinDistance = 2.0f;
		
//		new Thread(this).start();
		

	}
	
	
	/**
	 * Register a GestureCompleteListener for when a gesture is completed.
	 * @param listener The GestureCompleteListener to be registered.
	 */
	public void registerGestureCompleteListener(GestureCompleteListener listener) {
		mGestureCompleteListeners.add(listener);
	}
	
	/**
	 * Unregisters a GestureCompleteListener.
	 * @param listener The GestureCompleteListener to be unregistered.
	 */
	public void unregisterGestureCompleteListener(GestureCompleteListener listener) {
		mGestureCompleteListeners.remove(listener);
	}

	/**
	 * Registers a gesture and GestureListener combination. The listener will get called when the
	 * supplied gesture has been completed. 
	 * Note: Only 1 listener per gesture! If you try to register another listener to an already
	 * defined gesture, the previous listener will be unregistered.
	 * @param gesture The gesture which should invoke the listener.
	 * @param listener The GestureListener to be invoked.
	 * @return
	 */
	public boolean registerGesture(String gesture, GestureListener listener) {
		int gestureLength = gesture.length();
		boolean valid = true;
		for (int i = 0; i < gestureLength && valid; ++i)
			valid = isValidDirection(gesture.charAt(i));
		if (valid) {
			mGestureListeners.put(gesture, listener);
		}
		return valid;
	}
	
	private boolean isValidDirection(char direction) {
		String dir = String.valueOf(direction).toUpperCase();
		return dir.equals("U") || dir.equals("D") || dir.equals("L") || dir.equals("R");
	}
	
	private void gestureRecognizer(String gesture) {
		GestureListener listener = mGestureListeners.get(gesture);
		if (listener != null)
			listener.onRecognized();			
	}

	private void notifyGestureCompleteListeners(String gesture) {
		for (GestureCompleteListener listener : mGestureCompleteListeners)
			listener.onGestureCompleted(gesture);
	}

	/**
	 * This method will interpret the MotionEvents provided as parameter.
	 * You should invoke this method in your Activity.onTouchEvent(MotionEvent event)
	 * @param event The event to interpret
	 */
	int cnt = 0;
	int nMinX = 7;
	int nDiag = 3;
	boolean bFirstArea = false;
	boolean bSecondArea = false;
//	threadChk thread  = null;
//	SharedArea sharedArea = null;
	
	public void EndType()
	{
			
//		if (mDebug)
//			Log.d(TAG, "CNT: " + cnt);
		
		switch (cnt)
		{
		case 1:mStr = mStr1;break;
		case 2:mStr = mStr1 + mStr2;break;
		case 3:mStr = mStr1 + mStr2 + mStr3;break;
		case 4:mStr = mStr1 + mStr2 + mStr3 + mStr4;break;
		case 5:mStr = mStr1 + mStr2 + mStr3 + mStr4 + mStr5;break;
		case 6:mStr = mStr1 + mStr2 + mStr3 + mStr4 + mStr5+mStr6;break;
		case 7:mStr = mStr1 + mStr2 + mStr3 + mStr4 + mStr5+mStr6+mStr7;break;
		default:break;
		}
		
		cnt = 0;
		mGesture = mStr;
		if (mGesture != null)
		{
			String gesture = mGesture;
			notifyGestureCompleteListeners(gesture);
			gestureRecognizer(gesture);
			gesture = "";
		}
//		if (mDebug)
//			Log.d(TAG, "Gestures  " + mGesture);
		
		mStr = new String();mStr1 = new String();mStr2 = new String();mStr3 = new String();
		mStr4 = new String();mStr5 = new String();mStr6 = new String();mStr7 = new String();
		mGesture = new String();
	}
	
    public void touchEvent(MotionEvent event) {
    
    	int eventAction = event.getAction();
    	
 		tabHost = KauiTab.tabHost;
		if (tabHost != null)
		strTabTag = tabHost.getCurrentTabTag();
		
		if (strTabTag == strTabTagEdit) bTabEdit = true;
		else bTabEdit = false;
		
		if (!bTabEdit)
		{
			nJaX = 0;
			nJaY = 560;
			nJaW = 10;
			nJaH = 410;
		}
    
    	if (eventAction == MotionEvent.ACTION_DOWN 
    			&& event.getX()>nJaX && event.getX()<nJaW && event.getY()>nJaY && event.getY()<nJaH )
    	{		
    		if (timer != null)
    			timer.cancel();
    		
			if (bSecondArea && mGesture.length() > 1) {
				EndType();
			}
			bFirstArea = true;
			bSecondArea = false;
			cnt++;

			mGesture = "_"; // For convenience only, erases the need of a lot of
			// index bounds tests
			mGestureX = -1;
			mGestureY = -1;

		}

		else if (eventAction == MotionEvent.ACTION_DOWN
				&& (event.getX() < nJaX || event.getX() > nJaW
						|| event.getY() < nJaY || event.getY() > nJaH)
				&& mGesture != null && (!bTabEdit) ) {
			
			if (timer != null)
    			timer.cancel();
			if (bSecondArea && mGesture.length() > 1) {
				EndType();
			}
				bFirstArea = true;
				bSecondArea = false;
				cnt++;

				mGesture = "+"; // For convenience only, erases the need of a lot of
				// index bounds tests
				mGestureX = -1;
				mGestureY = -1;
		}

    	
    	else if (eventAction == MotionEvent.ACTION_DOWN 
    			&& event.getX()>nMoX && event.getX()<nMoW && event.getY()>nMoY && event.getY()<nMoH )
    	{
    		if (timer != null)
			timer.cancel();
		
    		if (bFirstArea  && mGesture.length() > 1)
			{
    			EndType();
			}
//    		if (thread != null)
//    			thread.suspend();
    		
    		bFirstArea = false;
    		bSecondArea = true;
    			cnt ++;

        		mGesture = "|"; // For convenience only, erases the need of a lot of index bounds tests
    			mGestureX = -1;
    			mGestureY = -1;
    			mDownMoX = event.getX();
    			mDownMoY = event.getY();
    	}
	  
    	else if (eventAction == MotionEvent.ACTION_MOVE) {
    		if (mGestureX == -1 || mGestureY == -1) 
    		{
    			mGestureX = event.getX();
    			mGestureY = event.getY();
    		} 
    		else 
    		{
    			if (mGesture.length() > 0)
    			{
    				if (bFirstArea)
	    			{
					float x = event.getX();
					float y = event.getY();

					float dist = (float) Math.sqrt(Math.pow(mGestureX - x, 2)
							+ Math.pow(mGestureY - y, 2));
						if (dist < mMinDistance)
							return;

					float mX = mGestureX - x;
					float mY = mGestureY - y;

						// ///////// ORG ///////
						if (Math.abs(mX) * 3 < Math.abs(mY))
						{
							if (Math.abs(mX) < Math.abs(mY))
							{
								if (mGestureY - y == 0)
									;
								else if (mGestureY - y > nMinX) {
									if (mGesture.charAt(mGesture.length() - 1) != 'U')
										mGesture += "U";
								} else if (mGestureY - y < -nMinX) {
									if (mGesture.charAt(mGesture.length() - 1) != 'D')
										mGesture += "D";
								}
							}
						}

						else if (Math.abs(mX) > Math.abs(mY) * 3)
						{
							if (Math.abs(mX) > Math.abs(mY))
								if (mGestureX - x == 0)
									;
								else if (mGestureX - x > nMinX) {
									if (mGesture.charAt(mGesture.length() - 1) != 'L')
										mGesture += "L";
								} else if (mGestureX - x < -nMinX) {
									if (mGesture.charAt(mGesture.length() - 1) != 'R')
										mGesture += "R";
								}
						}
						// ////////// ORG /////////

						if (mX < 0 && mY < 0 && Math.abs(mX - mY) < nDiag) {
							if (Math.abs(mX + mY) > nMinX) {
								if (mGesture.charAt(mGesture.length() - 1) != '1')
									mGesture += "1";
							}
						}

						else if (mX > 0 && mY > 0 && Math.abs(mX - mY) < nDiag) {
							if (Math.abs(mX + mY) > nMinX) {
								if (mGesture.charAt(mGesture.length() - 1) != '2')
									mGesture += "2";
							}
						}

						else if (mX > 0 && mY < 0 && Math.abs(mX + mY) < nDiag) {
							if ((mX + Math.abs(mY)) > nMinX) {
								if (mGesture.charAt(mGesture.length() - 1) != '3')
									mGesture += "3";
							}
						}

						else if (mX < 0 && mY > 0 && Math.abs(mX + mY) < nDiag) {
							if ((Math.abs(mX) + mY) > nMinX) {
								if (mGesture.charAt(mGesture.length() - 1) != '4')
									mGesture += "4";
							}
						}
						mGestureX = event.getX();
						mGestureY = event.getY();
						switch (cnt) {
						case 1:mStr1 = mGesture;break;
						case 2:mStr2 = mGesture;break;
						case 3:mStr3 = mGesture;break;
						case 4:mStr4 = mGesture;break;
						case 5:mStr5 = mGesture;break;
						case 6:mStr6 = mGesture;break;
						
						default:
							mStr = mGesture;break;
						}
					}
				}
    		} 
    		
    	} 
    	
    	else if (eventAction == MotionEvent.ACTION_DOWN 
    			&& (event.getX()<nJaX || event.getX()>nJaW || event.getY()<nJaY || event.getY()>nJaH)
    			&& mGesture != null && (bTabEdit) )
    	{
    		bFirstArea = false;
    		bSecondArea = false;
    		EndType();
    		cnt = 0;
    	}
    	
    	
    	else if (eventAction == MotionEvent.ACTION_UP)
    	{
    		timer = new CountDownTimer(nTimeInter, nTimeInter) {     
				public void onTick(
						long millisUntilFinished) {         
						
					}     
				public void onFinish() {         
					EndType();
					
					}  
				};
			timer.start();
			
    		if (bSecondArea)
    		{	
    			
    			
	    		float fUpMoX = event.getX();
	    		float fUpMoY = event.getY();
    		
	    		float fDiffX = Math.abs(fUpMoX-mDownMoX);
	    		float fDiffY = Math.abs(fUpMoY-mDownMoY);
	    		if (fDiffX > fDiffY)
	    		{
	    			if (fDiffX > 2 && fDiffX < 45)
		    		{
	    				mGesture += "l";
		    		}
	    			else if (fDiffX >= 45 && fDiffX < 150)
	    			{
	    				mGesture += "r";
	    			}
	    		}
	    		else 
	    		{
	    			if (fDiffY > 2 && fDiffY < 45)
		    		{
	    				mGesture += "u";
		    		}
	    			else if (fDiffY >= 45 && fDiffY < 150)
	    			{	
	    				mGesture += "d";
	    			}
	    		
	    		}
	    		int nLeng = mGesture.length();
	    		mStr =mGesture.substring(nLeng-1);
	    		
	    		switch (cnt) {
				case 1:mStr1 = mGesture;break;
				case 2:mStr2 = mGesture;break;
				case 3:mStr3 = mGesture;break;
				case 4:mStr4 = mGesture;break;
				case 5:mStr5 = mGesture;break;
				case 6:mStr6 = mGesture;break;
				case 7:mStr7 = mGesture;break;
				
				default:
					mStr = mGesture;break;
	    		}
	    		
    		}
    	}
    	else
    	{
    		bFirstArea = false;
    		bSecondArea = false;
    		return ;
    	}
    		
	}
    	
	private String mGesture;
	private String mStr, mStr1, mStr2 ,mStr3 , mStr4,
					mStr5, mStr6, mStr7 ;
	private float mGestureX;
	private float mGestureY;
	
	private float mDownMoX;
	private float mDownMoY;
	private boolean mDebug;
	//! Minimal distance between 2 points to be counted as valid.
	private float mMinDistance;
//	private int nJaX = 0;
//	private int nJaY = 560;
//	private int nJaW = 10;
//	private int nJaH = 110;
	
	private int nJaX = 0;
	private int nJaY = 260-160;
	private int nJaW = 160;
	private int nJaH = 410;
	
	private int nMoX = 160;
	private int nMoY = nJaY;
	private int nMoW = 310;
	private int nMoH = nJaH;
	
	private int nTimeInter = 250;
	private CountDownTimer timer;
	public TabHost tabHost;
	public String strTabTag;
	private static String strTabTagEdit = "eDit";
	public boolean bTabEdit;
	
	
	private ArrayList<GestureCompleteListener> mGestureCompleteListeners;
	private HashMap<String, GestureListener> mGestureListeners;
}

